package com.mouse.magent.common.net;

import com.mouse.magent.common.handler.BaseChannelInitializer;
import com.mouse.magent.common.handler.BaseHandler;
import com.mouse.magent.common.service.BaseChannelInit;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TcpServer {


    @Getter
    private Channel channel;
    @Getter
    private DefaultChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public synchronized void bind(int port, ChannelInitializer channelInitializer) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            connect(bossGroup, workerGroup, port, channelInitializer);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            throw e;
        }
    }


    public synchronized void bind(int port, BaseChannelInit channelInit) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        BaseHandler handler = new BaseHandler(channelGroup, channelInit.getMessageAction());
        BaseChannelInitializer channelInitializer = new BaseChannelInitializer(handler);
        try {
            connect(bossGroup, workerGroup, port, channelInitializer);
        } catch (Exception e) {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            log.error(e.getMessage(), e);
        }
    }

    public synchronized void bind(int port, BaseHandler handler, BaseChannelInit channelInit) throws Exception {
        handler.setCommandActionList(channelInit.getMessageAction());
        handler.setChannelGroup(channelGroup);

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        BaseChannelInitializer channelInitializer = new BaseChannelInitializer(handler);
        try {
            connect(bossGroup, workerGroup, port, channelInitializer);
        } catch (Exception e) {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            log.error(e.getMessage(), e);
        }
    }


    private void connect(EventLoopGroup bossGroup, EventLoopGroup workerGroup, int port, ChannelHandler channelHandler) throws Exception {
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(channelHandler)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        channel = b.bind(port).sync().channel();
        channel.closeFuture().addListener((ChannelFutureListener) future -> {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        });
    }

    public synchronized void close() {
        if (channel != null) {
            channel.close();
        }
    }
}
